package com.avocado.configuration.service.impl;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.criteria.Predicate;

import com.avocado.commons.utils.ExtendedStringUtils;
import com.avocado.configuration.dto.SequenceAddDto;
import com.avocado.configuration.dto.SequenceEditDto;
import com.avocado.configuration.dto.SequenceQueryDto;
import com.avocado.configuration.entity.Sequence;
import com.avocado.configuration.repository.SequenceRepository;
import com.avocado.configuration.service.SequenceService;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;


@Service
public class SequenceServiceImpl implements SequenceService {

	private final SequenceRepository sequenceRepository;

    public SequenceServiceImpl(SequenceRepository sequenceRepository) {
        this.sequenceRepository = sequenceRepository;
    }


    @Override
	public Sequence getOne(Long id) {
		
        return sequenceRepository.getOne(id);

	}

	@Override
	public Long add(SequenceAddDto dto) {
		
	    Sequence seq=new Sequence();

		BeanUtils.copyProperties(dto,seq);

		seq.setName(seq.getName().toUpperCase());

		sequenceRepository.saveAndFlush(seq);
		
       return seq.getId();
	}

	@Override
	public void update(SequenceEditDto dto) {

    	Sequence old=sequenceRepository.getOne(dto.getId());

    	BeanUtils.copyProperties(dto,old);

		sequenceRepository.saveAndFlush(old);

	}

	@Override
	public Page<Sequence> findByPage(Pageable pageable, SequenceQueryDto dto) {

     	 return sequenceRepository.findAll((root, criteriaQuery, criteriaBuilder) -> {

         List<Predicate> predicates = new ArrayList<>();

         if(!StringUtils.isEmpty(dto.getName())){

             predicates.add(criteriaBuilder.like(root.get("name").as(String.class),"%".concat(dto.getName()).concat("%")));

		 }

         Predicate[] predicateArray = new Predicate[predicates.size()];

         return criteriaBuilder.and(predicates.toArray(predicateArray));
         
     }, pageable);
     	 

	}

	@Override
	public List<Sequence> findAll(SequenceQueryDto dto) {

    	return sequenceRepository.findAll((root, criteriaQuery, criteriaBuilder) -> {

        List<Predicate> predicates = new ArrayList<>();

        if(!StringUtils.isEmpty(dto.getName())){
            predicates.add(criteriaBuilder.like(root.get("name").as(String.class),"%".concat(dto.getName()).concat("%")));
        }

        Predicate[] predicateArray = new Predicate[predicates.size()];

        return criteriaBuilder.and(predicates.toArray(predicateArray));
    });
    	 

	}

	@Override
	public Boolean deleteById(Long id) {

		Sequence old=sequenceRepository.getOne(id);

		sequenceRepository.delete(old);
		
		return Boolean.TRUE;
	}
	@Override
	@Transactional(propagation = Propagation.REQUIRES_NEW,rollbackFor=Exception.class)
	public String getNextValueBySeqName(String name){

		List<Sequence> list=sequenceRepository.findAllAndLockByName(name);

		if(list.isEmpty()){

			return null;
		}

		String nextValue="";

		for(Sequence t:list){

			nextValue=t.getPrefix()+ ExtendedStringUtils.fillString(t.getLength(), String.valueOf(t.getNextValue()), "0");

			t.setNextValue(t.getNextValue()+t.getAllocationSize());

			sequenceRepository.saveAndFlush(t);
		}

		return nextValue;
	}
	
	


}
